package com.zzs.common.security.exception.hander;

import com.zzs.common.core.enums.ResponseCode;
import com.zzs.common.core.response.Result;
import com.zzs.common.security.exception.ServiceException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.util.Objects;

/**
 * 全局异常处理器，统一拦截并处理应用中的异常。
 * 该类使用 {@link RestControllerAdvice} 进行全局异常捕获，并返回标准化的响应格式。
 * 主要作用：
 * <ul>
 *     <li>统一处理不同类型的异常，避免重复编写异常处理逻辑</li>
 *     <li>记录异常日志，方便问题排查</li>
 *     <li>保证 API 返回结构的一致性</li>
 * </ul>
 *
 * @author zzs
 * @date 2025/03/17
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 处理 HTTP 请求方法不支持异常，如 GET 请求访问 POST 接口。
     *
     * @param request 请求对象
     * @param e       异常对象
     * @return 标准错误响应
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<Void> handleHttpRequestMethodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException e) {
        log.error("请求地址'{}', 不支持'{}'请求", request.getRequestURI(), e.getMethod(), e);
        return Result.error(ResponseCode.METHOD_NOT_ALLOWED);
    }

    /**
     * 处理运行时异常（{@link RuntimeException}），通常表示未预料的错误。
     *
     * @param request 请求对象
     * @param e       异常对象
     * @return 标准错误响应
     */
    @ExceptionHandler(RuntimeException.class)
    public Result<Void> handleRuntimeException(HttpServletRequest request, RuntimeException e) {
        log.error("请求地址'{}', 发生异常", request.getRequestURI(), e);
        return Result.error(ResponseCode.INTERNAL_SERVER_ERROR);
    }

    /**
     * 处理请求参数绑定异常（{@link BindException}），通常在参数校验失败时触发。
     *
     * @param request 请求对象
     * @param e       异常对象
     * @return 标准错误响应，包含详细的错误信息
     */
    @ExceptionHandler(BindException.class)
    public Result<Void> handleBindException(HttpServletRequest request, BindException e) {
        log.error("请求地址'{}', 发生异常", request.getRequestURI(), e);
        return Result.error(ResponseCode.BAD_REQUEST, Objects.requireNonNull(e.getFieldError()).getDefaultMessage());
    }

    /**
     * 处理业务异常（{@link ServiceException}），用于封装自定义的业务错误。
     *
     * @param request 请求对象
     * @param e       业务异常对象
     * @return 标准错误响应，返回具体的业务错误信息
     */
    @ExceptionHandler(ServiceException.class)
    public Result<Void> handleServiceException(HttpServletRequest request, ServiceException e) {
        log.error("请求地址'{}', 发生异常", request.getRequestURI(), e);
        return Result.error(e.getResponseCode(), e.getMessage());
    }

    /**
     * 处理资源未找到异常（{@link NoResourceFoundException}），通常在请求无效资源时触发。
     *
     * @param request 请求对象
     * @param e       异常对象
     * @return 标准错误响应
     */
    @ExceptionHandler(NoResourceFoundException.class)
    public Result<Void> handleNoResourceFoundException(HttpServletRequest request, NoResourceFoundException e) {
        log.error("请求地址'{}', 不支持请求", request.getRequestURI(), e);
        return Result.error(ResponseCode.NOT_FOUND);
    }

    /**
     * 处理文件上传大小超限异常（{@link MaxUploadSizeExceededException}）。
     *
     * @param request 请求对象
     * @param e       异常对象
     * @return 标准错误响应，提示文件过大
     */
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public Result<Void> handleMaxUploadSizeExceededException(HttpServletRequest request, MaxUploadSizeExceededException e) {
        log.error("请求地址'{}', 发生异常", request.getRequestURI(), e);
        return Result.error(ResponseCode.FILE_TOO_LARGE);
    }

    @ExceptionHandler(NumberFormatException.class)
    public Result<Void> handleNumberFormatException(HttpServletRequest request, NumberFormatException e) {
        log.error("请求地址'{}', 发生异常", request.getRequestURI(), e);
        return Result.error(ResponseCode.BAD_REQUEST);
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<Void> handleHttpMessageNotReadableException(HttpServletRequest request, HttpMessageNotReadableException e) {
        log.error("请求地址'{}', 发生异常", request.getRequestURI(), e);
        return Result.error(ResponseCode.BAD_REQUEST);
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result<Void> handleMethodArgumentTypeMismatchException(HttpServletRequest request, MethodArgumentTypeMismatchException e) {
        log.error("请求地址'{}', 发生异常", request.getRequestURI(), e);
        return Result.error(ResponseCode.BAD_REQUEST);
    }

    @ExceptionHandler(DuplicateKeyException.class)
    public Result<Void> handleDuplicateKeyException(HttpServletRequest request, DuplicateKeyException e) {
        log.error("请求地址'{}', 发生异常", request.getRequestURI(), e);
        return Result.error(ResponseCode.RESOURCE_CONFLICT);
    }

    /**
     * 处理所有未知异常，作为最后的异常兜底处理。
     *
     * @param request 请求对象
     * @param e       异常对象
     * @return 标准错误响应，避免异常泄露到前端
     */
    @ExceptionHandler(Exception.class)
    public Result<Void> handleException(HttpServletRequest request, Exception e) {
        log.error("请求地址'{}', 发生异常", request.getRequestURI(), e);
        return Result.error(ResponseCode.INTERNAL_SERVER_ERROR);
    }
}
